在Yocto环境中添加自定义应用程序和库
概述
本文档指导用户在Yocto构建系统中添加自定义应用程序和库文件(以helloworld为例)。通过以下步骤,您可以将自己的代码集成到Yocto项目中,并生成包含这些组件的安装包和库以供使用。
目录
准备环境
安装准备
- 安装必要的支持软件包。
- 克隆代码。
具体的环境准备见:开发环境准备
创建项目目录
- 设定目录结构以便于管理和开发。
meta-custom/
├── conf/
│ └── layer.conf
├── recipes-apps/
│ └── helloworld/
│ ├── files/
│ │ ├── helloworld.c
│ │ ├── Makefile
│ │ └── helloworld.service
│ └── helloworld_1.0.bb
└── recipes-libs/
└── lib-helloworld/
├── files/
│ ├── lib_helloworld.c
│ ├── lib_helloworld.h
│ └── Makefile
└── lib-helloworld_1.0.bb
新增APP
创建应用程序文件
创建层目录
mkdir -p ${YOCTO_DIR}/layers/meta-custom/recipes-apps/helloworld/files
mkdir -p ${YOCTO_DIR}/layers/meta-custom/conf
配置层
编辑
layers/meta-custom/conf/layer.conf
文件:BBPATH .= ":${LAYERDIR}" BBFILES += "${LAYERDIR}/recipes-*/*/*.bb" LAYERDEPENDS_meta-custom = "core" LAYERSERIES_COMPAT_meta-custom = "kirkstone"
将以下内容添加到
layers/meta-qcom-distro/conf/bblayers.conf
:BBLAYERS = " ${WORKSPACE}/layers/meta-custom \ "
同时在
layers/meta-quectel/recipes-products/images/ qcom-multimedia-image.bbappend
添加以下内容:IMAGE_INSTALL:append = "helloworld" IMAGE_INSTALL:append = " \ lib-helloworld \ lib-helloworld-dev \ lib-helloworld-staticdev \ "
创建应用程序源代码
在
meta-custom/recipes-apps/helloworld/files
目录下创建helloworld.c
:// helloworld.c #include <stdio.h> int main() { printf("Hello, world!\n"); return 0; }
编写Makefile
在
meta-custom/recipes-apps/helloworld/files
下创建Makefile
:# 使用Yocto提供的编译标志 all: helloworld helloworld: helloworld.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< clean: rm -f helloworld .PHONY: all clean
创建Systemd服务文件
在
meta-custom/recipes-apps/helloworld/files
下创建helloworld.service
:[Unit] Description=Hello World Service [Service] Type=simple ExecStart=/usr/bin/helloworld [Install] WantedBy=multi-user.target
编写BitBake配方
在
meta-custom/recipes-apps/helloworld/
下创建helloworld_1.0.bb
:SUMMARY = "Hello World application" DESCRIPTION = "A simple Hello World application." LICENSE = "MIT" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" # 源代码文件列表(包含helloworld.c源文件、Makefile和systemd服务文件) SRC_URI = "file://helloworld.c \ file://Makefile \ file://helloworld.service" # 设置工作目录(${WORKDIR}是BitBake构建时的工作目录) S = "${WORKDIR}" # 继承systemd类(添加对systemd服务的支持) inherit systemd # 定义systemd服务文件名(${PN}会自动替换为软件包名) SYSTEMD_SERVICE:${PN} = "helloworld.service" # 配置阶段(这里跳过配置阶段) do_configure () { bbnote skip do_configure # 记录跳过配置阶段的日志 } # 编译阶段 do_compile() { # 先执行make clean清理 oe_runmake -f ${S}/Makefile clean # 然后执行make编译 oe_runmake -f ${S}/Makefile } # 安装阶段 do_install() { # 创建安装目录(${D}是目标根目录,${bindir}通常是/usr/bin) install -d ${D}${bindir} # 安装helloworld可执行文件到/usr/bin,设置权限为755 install -m 0755 ${S}/helloworld ${D}${bindir} # 创建systemd服务目录(${systemd_system_unitdir}通常是/lib/systemd/system) install -d ${D}${systemd_system_unitdir} # 安装helloworld.service服务文件,设置权限为644 install -m 0644 ${S}/helloworld.service ${D}${systemd_system_unitdir} }
应用程序的构建与运行
设置构建环境
进入编译环境代码工作目录,配置编译环境:
source quectel_build/compile/build.sh
-用户可以根据自己需要去选择安装应用程序,采取单编或是rootfs 整编方式。
安装应用程序(单编,ipk安装)
在
meta-custom/recipes-apps/
目录下执行以下命令:bitbake helloworld
构建完成后,生成的
.ipk
文件位于:find ~/build-qcom-wayland/tmp-glibc/deploy -name "helloworld*.ipk" /home/quectel/build-qcom-wayland/tmp-glibc/deploy/ipk/armv8-2a/helloworld_1.0-r0_armv8-2a.ipk
将生成的
.ipk
文件推送至设备:adb push .\helloworld_1.0-r0_armv8-2a.ipk /mnt
安装
.ipk
文件:# 安装前需挂载文件系统为读写模式 mount -o remount,rw /usr root@qcm6490-idp:/mnt# opkg install helloworld_1.0-r0_armv8-2a.ipk
验证安装:
root@qcm6490-idp:/mnt# /usr/bin/helloworld Hello, world!
安装应用程序(rootfs 整编)
在
meta-custom/recipes-apps/
目录下执行以下命令:#用户可自定义输入 "ProjectName" "ProjectRev” "CustName",从提示的 Valid Projects 和 Valid CUST_NAME 里面选择当前有效的字段进行用户定制。 buildconfig QSM565DWF SG565DWFPARL1A01_BL01BP01K0M01_QDP_LP6.6.0XX.01.00X_V0X STD #上述命令完成后执行 buildall buildall #上述命令完成后执行 buildpackage buildpackage
生成的镜像包含在
quectel_build/SG565DWFPARL1A01_BL01BP01K0M01_QDP_LP6.6.0XX.01.00X_V0X
路径下,
用户可参考链接使用 Yocto 构建 PI-SG565D 单板电脑镜像
和 QDL 介绍和镜像烧录
.
进行烧录。
- 验证安装:
root@qcm6490-idp:~# /usr/bin/helloworld Hello, world!
添加第三方库
创建库文件
创建层目录
mkdir -p ${YOCTO_DIR}/layers/meta-custom/recipes-libs/lib-helloworld/files
创建库源代码
在
meta-custom/recipes-libs/lib-helloworld/files/
下创建lib_helloworld.c
和lib_helloworld.h
:// lib_helloworld.c #include <stdio.h> void hello_print(const char* name) { printf("[LIB] Hello, %s!\n", name); }
// lib_helloworld.h #ifndef LIB_HELLO_H #define LIB_HELLO_H void hello_print(const char*); #endif
编写Makefile
在
meta-custom/recipes-libs/lib-helloworld/files
下创建Makefile
:
```Makefile
LIB_VERSION = "1.0"all: ${CC} ${CFLAGS} -fPIC -c lib_helloworld.c -o lib_helloworld.o ${CC} ${CFLAGS} -fPIC -shared lib_helloworld.o -o libhello.so.${LIB_VERSION} \ -Wl,-soname,libhello.so.1 ${LDFLAGS} ar rcs libhello.a lib_helloworld.o ln -sf libhello.so.${LIB_VERSION} libhello.so ln -sf libhello.so.${LIB_VERSION} libhello.so.1 clean: rm -f libhello.so* rm -f lib_helloworld.o rm -f libhello.a ```
编写BitBake配方
在
meta-custom/recipes-libs/lib-helloworld/
下创建lib-helloworld_1.0.bb
:SUMMARY = "Hello World Library" SECTION = "libs" LICENSE = "MIT" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" SRC_URI = "file://lib_helloworld.c \ file://Makefile \ file://lib_helloworld.h" S = "${WORKDIR}" EXTRA_OEMAKE = "'CC=${CC}' 'CFLAGS=${CFLAGS} -fPIC' 'LDFLAGS=${LDFLAGS}'" do_install() { # 1. 创建目标目录 install -d ${D}${libdir} # 2. 安装共享库并创建符号链接 install -m 0755 ${S}/libhello.so.${PV} ${D}${libdir}/ ln -sf libhello.so.${PV} ${D}${libdir}/libhello.so ln -sf libhello.so.${PV} ${D}${libdir}/libhello.so.1 # 3. 安装静态库 install -m 0644 ${S}/libhello.a ${D}${libdir}/ } # 包文件分配 FILES:${PN} = " \ ${libdir}/libhello.so.1 \ ${libdir}/libhello.so.${PV} \ " FILES:${PN}-dev = " \ ${libdir}/libhello.so \ " FILES:${PN}-staticdev = " \ ${libdir}/libhello.a \ "
库的构建与使用
设置构建环境
进入编译环境代码工作目录,配置编译环境:
source quectel_build/compile/build.sh
三方库的使用(bitbake单编)
bitbake构建:
bitbake lib-helloworld
根目录下搜索生成的动态库文件:
find ./* -name "libhello*"
将库文件推送至设备:
adb push libhello.so libhello.so.1 libhello.so.1.0 libhello.a /usr/lib
修复执行权限并重建符号链接:
chmod +x /usr/lib/libhello.so /usr/lib/libhello.so.1 /usr/lib/libhello.so.1.0 /usr/lib/libhello.a ln -sf libhello.so.1.0 libhello.so.1 ln -sf libhello.so.1 libhello.so
编写测试程序:
// static_test_helloworld.c #include <stdio.h> void hello_print(const char*); int main() { printf("static lib test\n"); hello_print("world"); return 0; } //dynamic_test_helloworld.c #include <stdio.h> void hello_print(const char*); int main() { printf("dynamic lib test\n"); hello_print("world"); return 0; }
编译并运行测试程序:
#静态库测试 gcc static_test_helloworld.c -lhello -static -o static_hello ./static_hello # 输出: static lib test [LIB] Hello, world! #动态库测试 gcc dynamic_test_helloworld.c /usr/lib/libhello.so -o dynamic_hello ./dynamic_hello # 输出: dynamic lib test [LIB] Hello, world!
三方库的使用(rootfs整编)
编译和烧录可参考上述安装应用程序(rootfs 整编)中的方法
验证使用(需要参考三方库的使用描述的编写测试程序):
/mnt# ls -l /usr/lib/libhello* -rw-r--r--. 2 root root 5002 Jan 1 1970 /usr/lib/libhello.a lrwxrwxrwx. 1 root root 15 Jul 25 06:26 /usr/lib/libhello.so -> libhello.so.1.0 lrwxrwxrwx. 1 root root 15 Jul 25 06:26 /usr/lib/libhello.so.1 -> libhello.so.1.0 -rwxr-xr-x. 2 root root 5968 Jan 1 1970 /usr/lib/libhello.so.1.0 #静态库测试 gcc static_test_helloworld.c -lhello -static -o static_hello ./static_hello # 输出: static lib test [LIB] Hello, world! #动态库测试 gcc dynamic_test_helloworld.c /usr/lib/libhello.so -o dynamic_hello ./dynamic_hello # 输出: dynamic lib test [LIB] Hello, world!
结论
通过本文档的指导,用户可以在Yocto环境中顺利添加自定义应用程序和库,实现个性化的功能集成。